﻿#region The MIT License
// The MIT License
// 
// Copyright (c) 2009 octalforty studios
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#endregion
using System.Collections.Generic;

using NUnit.Framework;

using octalforty.Chinchillin.Actions.Sync;

using Rhino.Mocks;

namespace octalforty.Chinchillin.Tests.Actions.Sync
{
    [TestFixture()]
    public class SyncManagerTestFixture
    {
        [Test()]
        public void SyncOneWay()
        {
            var mocks = new MockRepository();

            var syncCallback = mocks.StrictMock<ISyncCallback<string, string>>();
            var syncManager = new SyncManager<string, string>(syncCallback, null, new SyncItemEqualityComparer<string, string>());

            using(mocks.Record())
            {
                Expect.Call(() => syncCallback.SkipLocalItem(
                    Arg<ISyncContext>.Is.Anything, IsA(SyncItem.MakeSyncItem("b", () => "b"))));
                Expect.Call(() => syncCallback.SkipLocalItem(
                    Arg<ISyncContext>.Is.Anything, IsA(SyncItem.MakeSyncItem("c", () => "c_"))));
                
                Expect.Call(() => syncCallback.DeleteLocalItem(
                    Arg<ISyncContext>.Is.Anything, IsA(SyncItem.MakeSyncItem("e", () => "e"))));
                Expect.Call(() => syncCallback.DeleteLocalItem(
                    Arg<ISyncContext>.Is.Anything, IsA(SyncItem.MakeSyncItem("d", () => "d_"))));

                Expect.Call(() => syncCallback.SyncRemoteItem(
                    Arg<ISyncContext>.Is.Anything, IsA(SyncItem.MakeSyncItem("a", "a"))));
                Expect.Call(() => syncCallback.SyncRemoteItem(
                    Arg<ISyncContext>.Is.Anything, IsA(SyncItem.MakeSyncItem("c_", "c"))));
                Expect.Call(() => syncCallback.SyncRemoteItem(
                    Arg<ISyncContext>.Is.Anything, IsA(SyncItem.MakeSyncItem("d", "d"))));
            } // using

            mocks.ReplayAll();

            var result = syncManager.SyncOneWay(
                new List<SyncItem<string, string>>
                    {
                        SyncItem.MakeSyncItem("a", "a"),
                        SyncItem.MakeSyncItem("b", "b"),
                        SyncItem.MakeSyncItem("c", "c_"),
                        SyncItem.MakeSyncItem("c_", "c"),
                        SyncItem.MakeSyncItem("d", "d"),
                    }, 
                new List<SyncItem<string, string>>
                    {
                        SyncItem.MakeSyncItem("b", "b"),
                        SyncItem.MakeSyncItem("c", "c_"),
                        SyncItem.MakeSyncItem("d", "d_"),
                        SyncItem.MakeSyncItem("e", "e"),
                    });

            Assert.AreEqual(new SyncResult(2, 2, 3), result);

            mocks.VerifyAll();
        }

        [Test()]
        public void SyncOneWayWithEmptyTarget()
        {
            var mocks = new MockRepository();

            var syncCallback = mocks.StrictMock<ISyncCallback<string, string>>();
            var syncManager = new SyncManager<string, string>(syncCallback, null);

            using(mocks.Record())
            {
                Expect.Call(() => syncCallback.SyncRemoteItem(
                    Arg<ISyncContext>.Is.Anything, IsA(SyncItem.MakeSyncItem("a", "a"))));
                Expect.Call(() => syncCallback.SyncRemoteItem(
                    Arg<ISyncContext>.Is.Anything, IsA(SyncItem.MakeSyncItem("b", "b"))));
                Expect.Call(() => syncCallback.SyncRemoteItem(
                    Arg<ISyncContext>.Is.Anything, IsA(SyncItem.MakeSyncItem("c", "c_"))));
                Expect.Call(() => syncCallback.SyncRemoteItem(
                    Arg<ISyncContext>.Is.Anything, IsA(SyncItem.MakeSyncItem("d", "d"))));
            } // using

            mocks.ReplayAll();

            var result = syncManager.SyncOneWay(
                new List<SyncItem<string, string>>
                    {
                        SyncItem.MakeSyncItem("a", "a"),
                        SyncItem.MakeSyncItem("b", "b"),
                        SyncItem.MakeSyncItem("c", "c_"),
                        SyncItem.MakeSyncItem("d", "d"),
                    }, 
                new List<SyncItem<string, string>>());

            Assert.AreEqual(new SyncResult(0, 0, 4), result);

            mocks.VerifyAll();
        }

        [Test()]
        public void SyncOneWayWithEmptySource()
        {
            var mocks = new MockRepository();

            var syncCallback = mocks.StrictMock<ISyncCallback<string, string>>();
            var syncManager = new SyncManager<string, string>(syncCallback, null);

            using(mocks.Record())
            {
                Expect.Call(() => syncCallback.DeleteLocalItem(
                    Arg<ISyncContext>.Is.Anything, IsA(SyncItem.MakeSyncItem("a", "a"))));
                Expect.Call(() => syncCallback.DeleteLocalItem(
                    Arg<ISyncContext>.Is.Anything, IsA(SyncItem.MakeSyncItem("b", "b"))));
                Expect.Call(() => syncCallback.DeleteLocalItem(
                    Arg<ISyncContext>.Is.Anything, IsA(SyncItem.MakeSyncItem("c", "c_"))));
                Expect.Call(() => syncCallback.DeleteLocalItem(
                    Arg<ISyncContext>.Is.Anything, IsA(SyncItem.MakeSyncItem("d", "d"))));
            } // using

            mocks.ReplayAll();

            var result = syncManager.SyncOneWay(
                new List<SyncItem<string, string>>(),
                new List<SyncItem<string, string>>
                    {
                        SyncItem.MakeSyncItem("a", "a"),
                        SyncItem.MakeSyncItem("b", "b"),
                        SyncItem.MakeSyncItem("c", "c_"),
                        SyncItem.MakeSyncItem("d", "d"),
                    });

            Assert.AreEqual(new SyncResult(0, 4, 0), result);

            mocks.VerifyAll();
        }


        private static T IsA<T>(T value)
        {
            return Arg<T>.Is.Equal(value);
        }
    }
}
